﻿using Microsoft.AspNetCore.Mvc;
using Nop.Services.Localization;
using Nop.Services.Logging;
using Nop.Services.Messages;
using Nop.Services.ScheduleTasks;
using Nop.Services.Security;
using Nop.Web.Areas.Admin.Factories;
using Nop.Web.Areas.Admin.Infrastructure.Mapper.Extensions;
using Nop.Web.Areas.Admin.Models.Tasks;
using Nop.Web.Framework.Mvc;
using Nop.Web.Framework.Mvc.Filters;
using Nop.Web.Framework.Mvc.ModelBinding;

namespace Nop.Web.Areas.Admin.Controllers;

public partial class ScheduleTaskController : BaseAdminController
{
    #region Fields

    protected readonly ICustomerActivityService _customerActivityService;
    protected readonly ILocalizationService _localizationService;
    protected readonly INotificationService _notificationService;
    protected readonly IPermissionService _permissionService;
    protected readonly IScheduleTaskModelFactory _scheduleTaskModelFactory;
    protected readonly IScheduleTaskService _scheduleTaskService;
    protected readonly IScheduleTaskRunner _taskRunner;

    #endregion

    #region Ctor

    public ScheduleTaskController(ICustomerActivityService customerActivityService,
        ILocalizationService localizationService,
        INotificationService notificationService,
        IPermissionService permissionService,
        IScheduleTaskModelFactory scheduleTaskModelFactory,
        IScheduleTaskService scheduleTaskService,
        IScheduleTaskRunner taskRunner)
    {
        _customerActivityService = customerActivityService;
        _localizationService = localizationService;
        _notificationService = notificationService;
        _permissionService = permissionService;
        _scheduleTaskModelFactory = scheduleTaskModelFactory;
        _scheduleTaskService = scheduleTaskService;
        _taskRunner = taskRunner;
    }

    #endregion

    #region Methods

    public virtual IActionResult Index()
    {
        return RedirectToAction("List");
    }

    [CheckPermission(StandardPermission.System.MANAGE_SCHEDULE_TASKS)]
    public virtual async Task<IActionResult> List()
    {
        //prepare model
        var model = await _scheduleTaskModelFactory.PrepareScheduleTaskSearchModelAsync(new ScheduleTaskSearchModel());

        return View(model);
    }

    [HttpPost]
    [CheckPermission(StandardPermission.System.MANAGE_SCHEDULE_TASKS)]
    public virtual async Task<IActionResult> List(ScheduleTaskSearchModel searchModel)
    {
        //prepare model
        var model = await _scheduleTaskModelFactory.PrepareScheduleTaskListModelAsync(searchModel);

        return Json(model);
    }

    [HttpPost]
    [CheckPermission(StandardPermission.System.MANAGE_SCHEDULE_TASKS)]
    public virtual async Task<IActionResult> TaskUpdate(ScheduleTaskModel model)
    {
        //try to get a schedule task with the specified id
        var scheduleTask = await _scheduleTaskService.GetTaskByIdAsync(model.Id)
            ?? throw new ArgumentException("Schedule task cannot be loaded");

        //To prevent inject the XSS payload in Schedule tasks ('Name' field), we must disable editing this field, 
        //but since it is required, we need to get its value before updating the entity.
        if (!string.IsNullOrEmpty(scheduleTask.Name))
        {
            model.Name = scheduleTask.Name;
            ModelState.Remove(nameof(model.Name));
        }

        if (!ModelState.IsValid)
            return ErrorJson(ModelState.SerializeErrors());

        if (!scheduleTask.Enabled && model.Enabled)
            scheduleTask.LastEnabledUtc = DateTime.UtcNow;

        scheduleTask = model.ToEntity(scheduleTask);

        await _scheduleTaskService.UpdateTaskAsync(scheduleTask);

        //activity log
        await _customerActivityService.InsertActivityAsync("EditTask",
            string.Format(await _localizationService.GetResourceAsync("ActivityLog.EditTask"), scheduleTask.Id), scheduleTask);

        return new NullJsonResult();
    }

    [CheckPermission(StandardPermission.System.MANAGE_SCHEDULE_TASKS)]
    public virtual async Task<IActionResult> RunNow(int id)
    {
        try
        {
            //try to get a schedule task with the specified id
            var scheduleTask = await _scheduleTaskService.GetTaskByIdAsync(id)
                ?? throw new ArgumentException("Schedule task cannot be loaded", nameof(id));

            await _taskRunner.ExecuteAsync(scheduleTask, true, true, false);

            _notificationService.SuccessNotification(await _localizationService.GetResourceAsync("Admin.System.ScheduleTasks.RunNow.Done"));
        }
        catch (Exception exc)
        {
            await _notificationService.ErrorNotificationAsync(exc);
        }

        return RedirectToAction("List");
    }

    #endregion
}